#include "../include/logical_handler.h"
#include <iostream>
#include <nlohmann/json.hpp>
#include "../include/tcp_connection.h"
#include "../include/statusServer_client_rpc.h"
#include "../include/user_list_manger.h"
#include "../include/redis_pool.h"
#include "../include/user_dao.h"
#include "../include/chat_service_rpc_client.h"
#include "../include/chat_message_in_memory.h"

logical_handler::logical_handler(){
    init_handlers();
}

void logical_handler::get_func_and_execute(struct full_msg * msg)
{
    if(handlers.count(msg->message_id)==false){
        std::cout<<"没有对应的处理函数"<<std::endl;
        delete msg;
        return;
    }else{
        handlers[msg->message_id](msg);
        delete msg;
        return;
    }
}


void logical_handler::init_handlers()
{
    handlers.insert(std::make_pair(recv_package_id::CHAT_LOGIN,[this](struct full_msg * msg){
        this->handler_chat_login(msg);
    }));

    //暂时注释一下
    // handlers.insert(std::make_pair(recv_package_id::chat_text_msg,[this](struct full_msg * msg){
    //     this->handler_chat_text_msg(msg);
    // }));

    handlers.insert(std::make_pair(recv_package_id::SEARCH_USER,[this](struct full_msg * msg){
        this->handler_search_user(msg);
    }));

    handlers.insert(std::make_pair(recv_package_id::ADD_FRIEND_Apply,[this](struct full_msg * msg){
        this->handler_add_friend_apply(msg);
    }));

    handlers.insert(std::make_pair(recv_package_id::FRIEND_APPLY_RES,[this](struct full_msg * msg){
        this->handler_friend_apply_res(msg);
    }));

    handlers.insert(std::make_pair(recv_package_id::CHAT_TEXT_MSG,[this](struct full_msg * msg){
        this->handler_chat_text_msg(msg);
    }));



    
    






}

void logical_handler::handler_chat_login(struct full_msg * msg)
{
    
    std::cout<<"收到handler_chat_login 包"<<std::endl;

    nlohmann::json req_json;
    nlohmann::json res_json;

    try{
        req_json=nlohmann::json::parse(msg->body,msg->body+msg->body_len);
    }catch(const std::exception &e){

        std::cout<<"处理chat_login时json解析错误"<<std::endl;
        res_json["result"]=false;
        std::string str=res_json.dump();

        msg->tcp_con->async_write_msg(response_package_id::RESPONSE_CHAT_LOGIN,str.size(),str.c_str());
        //考虑返回错误给客户端
        return;
    }
    

    //向status发起rpc请求、
    std::string email=req_json["email"].get<std::string>();
    std::string token=req_json["token"].get<std::string>();
    bool flag=statusServer_client_rpc::get_instance()->check_token(email,token);
    //暂时就返回这么些数据....后续如果还有其他数据，那么就继续返回即可，反正是json格式数据
    if(flag){
        res_json["result"]=true;
        res_json["info"]="token校验成功";
        
    }else{
        res_json["result"]=false;
        res_json["info"]="token校验是失败";
    }
    
    if(flag){
        //进行redis操作，将该用户的email写入对应的user_list中，redis中，并更改该服务器的用户人数
        msg->tcp_con->email=email;
        user_list_manger::get_instance()->add_tcp_connection(email,msg->tcp_con);
        //获取redis实例
        MyRedis *one=redis_pool::get_instance()->get_one_redis();
        if(one==nullptr){
            //几乎不会走到这里
            std::cout<<"redis_pool里获取不到redis_pool实例了,统计出现问题"<<std::endl;
        }else{
            int redis_opt_res=one->hincrby(CHAT_SERVER,user_list_manger::get_instance()->char_server_field.c_str(),1);
            if(redis_opt_res==-1){
                std::cout<<"redis 设置 chat_server居然出错！！"<<std::endl;
            }
            redis_opt_res=one->sadd(user_list_manger::get_instance()->user_list_key.c_str(),email.c_str());
            if(redis_opt_res==-1){
                std::cout<<"redis 追加 user_list居然出错！！"<<std::endl;
            }
        }
    }
    
    

    std::string str=res_json.dump();

    msg->tcp_con->async_write_msg(response_package_id::RESPONSE_CHAT_LOGIN,str.size(),str.c_str());

    //顺便也将好友信息与申请信息（自己发送的申请与他人发送的申请）发送给客户端

    std::string user_info;
    
    get_and_set_user_info(email,user_info);
    
    msg->tcp_con->async_write_msg(response_package_id::RESPONSE_USER_INFO,user_info.size(),user_info.c_str());



}

void logical_handler::get_and_set_user_info(const std::string user_email, std::string &user_info)
{
    auto mysql_con=user_dao::get_instance()->new_get_con();
    mysql_con->_con->setAutoCommit(false);
    nlohmann::json user_info_json;
    user_dao::get_instance()->search_friend_list(mysql_con,user_email,user_info_json);
    user_dao::get_instance()->search_apply_list_from_self(mysql_con,user_email,user_info_json);
    user_dao::get_instance()->search_apply_list_from_other(mysql_con,user_email,user_info_json);

    user_info=user_info_json.dump(4);   //暂时设置为4，到时候打印出来看看，最终无参即可
    mysql_con->_con->commit();
    mysql_con->_con->setAutoCommit(true);
    std::cout<<user_info<<std::endl;
    user_dao::get_instance()->new_return_con(mysql_con);

}




void logical_handler::handler_search_user(struct full_msg *msg)
{
    std::cout<<"收到handler_search_user 包"<<std::endl;

    nlohmann::json req_json;
    nlohmann::json res_json;

    try{
        req_json=nlohmann::json::parse(msg->body,msg->body+msg->body_len);
    }catch(const std::exception &e){

        std::cout<<"处理search_user时json_解析错误"<<std::endl;
        res_json["result"]=false;
        std::string str=res_json.dump();

        msg->tcp_con->async_write_msg(response_package_id::RESPONSE_SEARCH_USER,str.size(),str.c_str());
        //考虑返回错误给客户端
        return;
    }

    //要引进mysql查询--通过tar_user_email去找到用户的信息
    struct search_user_res res=user_dao::get_instance()->search_user(req_json["from_user_email"].get<std::string>(),req_json["tar_user_email"].get<std::string>());
    
    if(res.tar_user_name.empty()){
        //数据为空就表明查询不到
        res_json["result"]=false;
        
    }else{
        res_json["result"]=true;
        res_json["user_name"]=res.tar_user_name;
        res_json["is_already_add"]=res.is_already_friend;
        
    }
    
    std::string str=res_json.dump();

    msg->tcp_con->async_write_msg(response_package_id::RESPONSE_SEARCH_USER,str.size(),str.c_str());

    return;

}


void logical_handler::handler_add_friend_apply(struct full_msg *msg){
    std::cout<<"收到handler_add_friend_apply包"<<std::endl;

    nlohmann::json req_json;
    nlohmann::json res_json;

    try{
        req_json=nlohmann::json::parse(msg->body,msg->body+msg->body_len);
    }catch(const std::exception &e){

        std::cout<<"处理add_friend_apply时json解析错误"<<std::endl;
        res_json["result"]=false;
        std::string str=res_json.dump();

        msg->tcp_con->async_write_msg(response_package_id::RESPONSE_ADD_FRIEND_Apply,str.size(),str.c_str());
        //考虑返回错误给客户端
        return;
    }
    std::string from_email=req_json["from_email"].get<std::string>();
    std::string to_email=req_json["to_email"].get<std::string>();
    std::string varify_text=req_json["varify_text"].get<std::string>();
    std::string from_name=req_json["from_name"].get<std::string>();
    //1.先去将数据入库
    auto mysql_con=user_dao::get_instance()->new_get_con();
    mysql_con->_con->setAutoCommit(false);
    //判断请求是否重复
    bool flag_is_need_forward=true;
    if(user_dao::get_instance()->friend_apply_is_repeat(mysql_con,from_email,to_email)){
        //如果存在，那么
        res_json["is_repeat"]=true;
        res_json["result"]=false;
        flag_is_need_forward=false;
    }else{
        res_json["result"]=true;
        user_dao::get_instance()->add_friend_apply(mysql_con,from_email,to_email,varify_text);
    }

    
    mysql_con->_con->setAutoCommit(true);
    mysql_con->_con->commit();

    user_dao::get_instance()->new_return_con(mysql_con);

    if(flag_is_need_forward==false){
        //这里返回消息即可
        std::string str=res_json.dump();

        msg->tcp_con->async_write_msg(response_package_id::RESPONSE_ADD_FRIEND_Apply,str.size(),str.c_str());
        return;
    }
    //判断是否在本服务器内
    auto tcp_connection=user_list_manger::get_instance()->find_and_get_con(to_email);
    if(tcp_connection==nullptr){
        //不在本服务器内，发送rpc服务去查找
        std::string tar_server=statusServer_client_rpc::get_instance()->get_forward_target(to_email);
        if(tar_server.empty()==false){
            //判断是否与本机的rpc_server相等
            if(tar_server==user_list_manger::get_instance()->rpc_service_address){
                std::cout<<"获得的to_email所在的服务器在本机，怎么可能！！,可能更新不及时"<<std::endl;
                //这里回包吧
                std::string str=res_json.dump();
                msg->tcp_con->async_write_msg(response_package_id::RESPONSE_ADD_FRIEND_Apply,str.size(),str.c_str());
                return;
            }
;            //不为空，发送通知
            //如果本地没找到-那么尝试去建立该条channel,然后发送rpc请求
            auto rpc_client_item=chat_service_rpc_client_pool::get_instance()->find_and_get_item(tar_server);
            if(rpc_client_item==nullptr){
                rpc_client_item=chat_service_rpc_client_pool::get_instance()->add_item(tar_server);
            }

            //那么就去发送即可
            //先去找到
            bool notify_res=rpc_client_item->notify_add_friend_apply(from_email,to_email,varify_text,from_name);
            
        }
    }else{
        //如果在本服务器内
        nlohmann::json other_res_json;
        other_res_json["from_email"]=from_email;
        other_res_json["to_email"]=to_email;
        other_res_json["from_name"]=from_name;
        other_res_json["varify_text"]=varify_text;
        std::string data=other_res_json.dump();

        tcp_connection->async_write_msg(response_package_id::RESPONSE_ADD_FRIEND_NOTIFY,data.size(),data.c_str());
        
    }

    //返回给发起端信息，表示接收到了
    


    std::string str=res_json.dump();

    msg->tcp_con->async_write_msg(response_package_id::RESPONSE_ADD_FRIEND_Apply,str.size(),str.c_str());
    return;

}


void logical_handler::handler_friend_apply_res(struct full_msg * msg){
    std::cout<<"收到handler_friend_apply_res包"<<std::endl;

    nlohmann::json req_json;
    nlohmann::json res_json;

    try{
        req_json=nlohmann::json::parse(msg->body,msg->body+msg->body_len);
    }catch(const std::exception &e){

        std::cout<<"处理friend_apply_res时json解析错误"<<std::endl;
        res_json["result"]=false;
        std::string str=res_json.dump();

        msg->tcp_con->async_write_msg(response_package_id::RESPONSE_FRIEND_APPLY_RES,str.size(),str.c_str());
        //考虑返回错误给客户端
        return;
    }

    std::string from_email=req_json["from_email"].get<std::string>();
    //这个to_email是本次发包端
    std::string to_email=req_json["to_email"].get<std::string>();
    int apply_res=0;
    if(req_json["apply_res"].get<bool>()){
        apply_res=1;
    }

    res_json["result"]=true;
    res_json["from_email"]=from_email;
    if(apply_res){
        res_json["apply_res"]=true;
    }else{
        res_json["apply_res"]=false;
    }
    
    auto mysql_con=user_dao::get_instance()->new_get_con();
    mysql_con->_con->setAutoCommit(false);

    int mod_res=user_dao::get_instance()->modify_apply_list(mysql_con,from_email,to_email,apply_res);
    if(mod_res!=1){
        mysql_con->_con->rollback();
        mysql_con->_con->setAutoCommit(true);
        user_dao::get_instance()->new_return_con(mysql_con);
        //回包
        res_json["result"]=false;
        std::string str=res_json.dump();
        msg->tcp_con->async_write_msg(response_package_id::RESPONSE_SEARCH_USER,str.size(),str.c_str());
        return;
    }

    if(apply_res){
        //是否同意，同意才添加好友
        if(user_dao::get_instance()->add_friend_list(mysql_con,from_email,to_email)!=0){
            mysql_con->_con->rollback();
            mysql_con->_con->setAutoCommit(true);
            user_dao::get_instance()->new_return_con(mysql_con);
            //回包
            res_json["result"]=false;
            std::string str=res_json.dump();
            msg->tcp_con->async_write_msg(response_package_id::RESPONSE_SEARCH_USER,str.size(),str.c_str());
            return;
        }
        
    }
    

    //这里完成mysql的操作，提交事务
    mysql_con->_con->commit();
    mysql_con->_con->setAutoCommit(true);
    user_dao::get_instance()->new_return_con(mysql_con);


    //进行转发
    auto tcp_connection=user_list_manger::get_instance()->find_and_get_con(from_email);
    if(tcp_connection==nullptr){
        //不在本服务器内，发送rpc服务去查找
        std::string tar_server=statusServer_client_rpc::get_instance()->get_forward_target(from_email);
        if(tar_server.empty()==false){
            //不为空，说明在线,后续发送通知
            //判断是否与本机的rpc_server相等
            if(tar_server==user_list_manger::get_instance()->rpc_service_address){
                std::cout<<"获得的to_email所在的服务器在本机，怎么可能！！,可能更新不及时"<<std::endl;
                //这里回包吧
                std::string str=res_json.dump();

                msg->tcp_con->async_write_msg(response_package_id::RESPONSE_FRIEND_APPLY_RES,str.size(),str.c_str());
                return;
            }
            
            auto rpc_client_item=chat_service_rpc_client_pool::get_instance()->find_and_get_item(tar_server);
            if(rpc_client_item==nullptr){
                //如果本地没找到-那么尝试去建立该条channel,然后发送rpc请求
                rpc_client_item=chat_service_rpc_client_pool::get_instance()->add_item(tar_server);
            }

            //那么就去发送相关rpc请求
            
            bool rpc_res=rpc_client_item->notify_friend_apply_res(from_email,to_email,apply_res);
            if(rpc_res){
                std::cout<<"本次rpc转发成功"<<std::endl;
            }
             
        }
    }else{
        //如果在本服务器内
        nlohmann::json other_res_json;
        
        other_res_json["to_email"]=to_email;
        if(apply_res){
            other_res_json["apply_res"]=true;
        }else{
            other_res_json["apply_res"]=false;
        }
        
        
        std::string data=other_res_json.dump();

        tcp_connection->async_write_msg(response_package_id::RESPONSE_FRIEND_APPLY_NOTIFY,data.size(),data.c_str());
        
    }


    std::string str=res_json.dump();

    msg->tcp_con->async_write_msg(response_package_id::RESPONSE_FRIEND_APPLY_RES,str.size(),str.c_str());
    return;



}




void logical_handler::handler_chat_text_msg(struct full_msg *msg){
    std::cout<<"收到handler_chat_text_msg包"<<std::endl;

    nlohmann::json req_json;
    nlohmann::json res_json;

    try{
        req_json=nlohmann::json::parse(msg->body,msg->body+msg->body_len);
    }catch(const std::exception &e){
        //几乎不可能到这里，如果真的到这里了，其实也没有回包的必要，客户端并不能锁定消息
        std::cout<<"处理chat_text_msg时json解析错误----也没有发送的必要，客户端拿到这个响应也无法定位msg"<<std::endl;

        // res_json["result"]=false;
        // std::string str=res_json.dump();

        // msg->tcp_con->async_write_msg(response_package_id::RESPONSE_CHAT_TEXT_MSG,str.size(),str.c_str());

        //考虑返回错误给客户端
        return;
    }
    //将数据解析出来
    std::string from_email=req_json["from_email"].get<std::string>();
    std::string to_email=req_json["to_email"].get<std::string>();
    int msg_type=req_json["msg_type"].get<int>();
    std::string msg_id=req_json["msg_id"].get<std::string>();

    std::string msg_data;
    if(msg_type==chatType::PLAIN_TEXT){
        msg_data=req_json["msg_data"].get<std::string>();
    }else if(msg_type==chatType::file){
        const nlohmann::json & file_json=req_json["msg_data"];
        msg_data=file_json.dump();
    }

   

    bool is_need_store_in_memory=false;

    //判断是否能否在内存中找到目标用户
    auto tcp_connection=user_list_manger::get_instance()->find_and_get_con(to_email);
    if(tcp_connection==nullptr){
        auto rpc_item=chat_service_rpc_client_pool::get_instance()->get_rpc_client_item_through_email(to_email);
        if(rpc_item==nullptr){
            std::cout<<"待转发对象不在线"<<std::endl;
            //持久化该条数据
            auto mysql_con=user_dao::get_instance()->new_get_con();
            //只执行一条，就没有必要显示开启事务了
            user_dao::get_instance()->insert_message(mysql_con,from_email,to_email,msg_type,msg_id,msg_data);

            user_dao::get_instance()->new_return_con(mysql_con);
            
          
        }else{
            //尝试转发该条信息---到这里要么存在缓存，要么通过rpc找到了目标
            bool rpc_res=rpc_item->notify_chat_text_msg(from_email,to_email,msg_type,msg_id,msg_data);
            if(rpc_res==false){
                //说明不在目标rpc所在服务器里,可能是缓存失效,先删除缓存，需要再度  
                user_list_manger::get_instance()->delete_one_client_server_cache(to_email);
                rpc_item=chat_service_rpc_client_pool::get_instance()->get_rpc_client_item_through_email(to_email);
                //这次几乎必中
                if(rpc_item==nullptr){
                    //进行持久化
                    auto mysql_con=user_dao::get_instance()->new_get_con();
                    //只执行一条，就没有必要显示开启事务了
                    user_dao::get_instance()->insert_message(mysql_con,from_email,to_email,msg_type,msg_id,msg_data);

                    user_dao::get_instance()->new_return_con(mysql_con);
                    

                }else{
                    rpc_res=rpc_item->notify_chat_text_msg(from_email,to_email,msg_type,msg_id,msg_data);
                    if(rpc_res==false){
                        //走到这里说明还没来得及更新---概率极小走到这里--两次找到同一个rpc_address,在两次rpc服务内还没有更新完，几乎不可能
                        is_need_store_in_memory=true;
                    }
                    
                }
            }
        }
    }else{
        //直接转发即可
        nlohmann::json other_res_json;
        other_res_json["from_email"]=from_email;
        other_res_json["to_email"]=to_email;
        other_res_json["msg_type"]=msg_type;
        other_res_json["msg_id"]=msg_id;
        if(msg_type==chatType::PLAIN_TEXT){
            other_res_json["msg_data"]=msg_data;
        }else if(msg_type==chatType::file){
            other_res_json["msg_data"]=req_json["msg_data"];
        }
        std::string data=other_res_json.dump();

        tcp_connection->async_write_msg(response_package_id::NOTIFY_CHAT_TEXT_MSG,data.size(),data.c_str());
        is_need_store_in_memory=true;

    }

    if(is_need_store_in_memory){
        //存到内存中去--会在erase时delete掉
        message_item *item=new message_item(from_email,to_email,msg_type,msg_id,msg_data);
       
        message_list::get_instance()->insert_message_item(msg_id,item);
    }

    res_json["msg_id"]=msg_id;
    res_json["result"]=true;
    res_json["to_email"]=to_email;
    std::string str=res_json.dump();

    msg->tcp_con->async_write_msg(response_package_id::RESPONSE_CHAT_TEXT_MSG,str.size(),str.c_str());
    return;




}


void logical_handler::handler_response_notify_chat_text_msg(struct full_msg *msg)
{
    //这个包不需要回应
    std::cout<<"收到handler_response_chat_text_msg包"<<std::endl;

    nlohmann::json req_json;
    nlohmann::json res_json;

    try{
        req_json=nlohmann::json::parse(msg->body,msg->body+msg->body_len);
    }catch(const std::exception &e){
        //这里几乎不可能
        std::cout<<"处理response_chat_text_msg时json解析错误----无需回包---但是怎么可能会执行到这里"<<std::endl;

        return;
    }
    //解析数据

    std::string msg_id=req_json["msg_id"].get<std::string>();
    //bool result=req_json["result"].get<bool>(); //这个没吊用

    //考虑加锁吧--加自旋锁--这个函数内部会加锁吗，外部不用管

    message_list::get_instance()->erase_message_item(msg_id);



}





